package modules

import (
	. "chess_platform/internal/common"
	"chess_platform/models/client"
	"chess_platform/models/h5"
	"chess_platform/models/partner"
	"chess_platform/models/pb"
	"chess_platform/models/pc"
	"errors"
	"fmt"
	"github.com/astaxie/beego/orm"
	"time"
)

//封装一些通用模块

//一级代理提成(二级代理开通)
func bonusLevel2Open(pid, childId, cardNum int64, multiOrm ...orm.Ormer) error {
	rule, err := h5.RuleByType(RuleLevel2Open) //第一次开通代理
	if err != nil {
		return err
	}
	if rule.Id == 0 {
		return errors.New("代理提成规则没有制定")
	}
	cn, err := h5.UpdateCash(rule.Amount, pid, false, multiOrm...)
	if err != nil {
		return err
	}
	if cn == 0 {
		return MsgErrDataBase
	}
	cr := map[string]interface{}{
		"agent_id":    pid,
		"child_id":    childId,
		"card_num":    cardNum,
		"amount":      rule.Amount,
		"type":        CashLevel2Open,
		"user_type":   Agent,
		"month":       CurrentYearMonth(),
		"create_time": time.Now().Unix(),
	}
	_, err = h5.NewCashRecord(cr, multiOrm...)
	if err != nil {
		return err
	}
	return nil
}

//一级代理收入: (二级代理进货)
func BonusLevel2Buy(pid, childId, cardNum int64, multiOrm ...orm.Ormer) error {
	if !h5.Level1AgentIsPass(pid) { //一级代理考不通过，一级代理的进货价同二级的一样，所以没有差价，也就没有提成
		return nil
	}

	// 有提成，二级代理进货价 减去 一级代理进货价(如果一级代理不合格，则进货价为二价的一样，则没有提成)
	level1Rule, err := h5.RuleByType(RuleLevel1CardPrice) //一级代理进货价
	if err != nil {
		return err
	}
	if level1Rule.Id == 0 {
		return errors.New("一级代理进货价规则没有制定")
	}

	level2Rule, err := h5.RuleByType(RuleLevel2CardPrice) //二级代理进货价
	if err != nil {
		return err
	}
	if level2Rule.Id == 0 {
		return errors.New("二级代理进货价规则没有制定")
	}

	cn, err := h5.UpdateCash((level2Rule.Amount-level1Rule.Amount)*cardNum, pid, false, multiOrm...)
	if err != nil {
		return err
	}
	if cn == 0 {
		return MsgErrDataBase
	}
	//提成记录
	cr := map[string]interface{}{
		"agent_id":    pid,
		"child_id":    childId,
		"card_num":    cardNum,
		"amount":      (level2Rule.Amount - level1Rule.Amount) * cardNum,
		"type":        CashLevel2Buy,
		"user_type":   Agent,
		"month":       CurrentYearMonth(),
		"create_time": time.Now().Unix(),
	}
	_, err = h5.NewCashRecord(cr, multiOrm...)
	return err
}

//一级代理收入:一级代理的玩家直充一级代理提成
func bonusPlayerLevel1(agentId, playerId, cardNum int64, multiOrm ...orm.Ormer) error {
	//获取玩家直充的进货价
	playerRule, err := h5.RuleByType(RulePlayerCardPrice)
	if err != nil {
		return err
	}
	if playerRule.Id == 0 {
		return errors.New("玩家直充进货价规则没有制定")
	}

	var rule Rule

	if !h5.Level1AgentIsPass(agentId) { //一级代理考核不通过,进货价同二级代理一样
		rule, err = h5.RuleByType(RuleLevel2CardPrice)
	} else { //考核通过
		rule, err = h5.RuleByType(RuleLevel1CardPrice)
	}
	if err != nil {
		return err
	}
	if rule.Id == 0 {
		return errors.New("代理进货价规则没有制定")
	}
	cn, err := h5.UpdateCash((playerRule.Amount-rule.Amount)*cardNum, agentId, false, multiOrm...)
	if err != nil {
		return err
	}
	if cn == 0 {
		return MsgErrDataBase
	}
	cr := map[string]interface{}{
		"agent_id":    agentId,
		"child_id":    playerId,
		"user_type":   Player,
		"card_num":    cardNum,
		"type":        CashAutomatic,
		"amount":      (playerRule.Amount - rule.Amount) * cardNum,
		"month":       CurrentYearMonth(),
		"create_time": time.Now().Unix(),
	}
	_, err = h5.NewCashRecord(cr, multiOrm...)
	if err != nil {
		return err
	}
	return nil

}

//一级代理收入与二级代理收入:二级代理的玩家直充二级代理提成,二级代理的玩家直充一级代理提成
func bonusPlayerLevel2(pid, uid, playerId, cardNum int64, multiOrm ...orm.Ormer) error {
	//获取玩家直充的进货价
	playerRule, err := h5.RuleByType(RulePlayerCardPrice)
	if err != nil {
		return err
	}
	if playerRule.Id == 0 {
		return errors.New("玩家直充进货价规则没有制定")
	}

	//---------------------------------------------------------
	//玩家直充:二级代理的玩家直充提成给二级
	level2Rule, err := h5.RuleByType(RuleLevel2CardPrice)
	if err != nil {
		return err
	}
	if level2Rule.Id == 0 {
		return errors.New("二级代理进货价规则没有制定")
	}
	cn1, err := h5.UpdateCash((playerRule.Amount-level2Rule.Amount)*cardNum, uid, false, multiOrm...)
	if err != nil {
		return err
	}
	if cn1 == 0 {
		return MsgErrDataBase
	}
	cr1 := map[string]interface{}{
		"agent_id":    uid,
		"child_id":    playerId,
		"user_type":   Player,
		"card_num":    cardNum,
		"type":        CashAutomatic,
		"amount":      (playerRule.Amount - level2Rule.Amount) * cardNum,
		"month":       CurrentYearMonth(),
		"create_time": time.Now().Unix(),
	}
	_, err = h5.NewCashRecord(cr1, multiOrm...)
	if err != nil {
		return err
	}

	//-------------------------------------------
	//玩家直充:二级代理的玩家直充提成给一级
	if !h5.Level1AgentIsPass(pid) { //一级代理考核不通过,没提成
		return nil
	}
	level1Rule, err := h5.RuleByType(RuleLevel1CardPrice)
	if err != nil {
		return err
	}
	if level1Rule.Id == 0 {
		return errors.New("代理提成规则没有制定")
	}

	cn, err := h5.UpdateCash((level2Rule.Amount-level1Rule.Amount)*cardNum, pid, false, multiOrm...)
	if err != nil {
		return err
	}
	if cn == 0 {
		return MsgErrDataBase
	}
	cr := map[string]interface{}{
		"agent_id":    pid,
		"child_id":    uid,
		"user_type":   Agent,
		"card_num":    cardNum,
		"type":        CashLevel2Automatic,
		"amount":      (level2Rule.Amount - level1Rule.Amount) * cardNum,
		"month":       CurrentYearMonth(),
		"create_time": time.Now().Unix(),
	}
	_, err = h5.NewCashRecord(cr, multiOrm...)
	return err
}

//因为二级代理进货或开通产生的提成(总函数)
func BonusAgent(order *Order, multiOrm ...orm.Ormer) error {
	//获取上级代理的uid
	field := []string{"pid", "level"}
	pu, err := h5.SpecifyUserInfoById(order.Uid, field)
	if err != nil {
		return err
	}
	if pu == nil {
		return errors.New(fmt.Sprintf("订单号:%v里代理:%d在h5_user没有找到", order.Id, order.Uid))
	}
	//如果此次充值为二级代理，要给上一级提成
	if pu.Level == Level2 {
		if order.IsFirst == FirstTimeBuyCard {
			//第一次开通代理
			err = bonusLevel2Open(pu.Pid, order.Uid, order.CardNum, multiOrm...)
		} else {
			//进货
			err = BonusLevel2Buy(pu.Pid, order.Uid, order.CardNum, multiOrm...)
		}
		if err != nil {
			return err
		}
	}

	return nil
}

//因为玩家直充而产生的提成,即把上面两个提成函数封装起来(总函数)
func BonusPlayer(order *Order, multiOrm ...orm.Ormer) error {
	//获取玩家代理的上级代理的uid,当然可能没有上级代理
	field := []string{"pid", "level"}
	u, err := h5.SpecifyUserInfoById(order.AgentId, field)
	if err != nil {
		return err
	}
	if u == nil { //
		return errors.New(fmt.Sprintf("玩家:%d没有找到对应的代理:%d,下单时出错", order.Uid, order.AgentId))
	}
	if u.Level == Level1 {
		err = bonusPlayerLevel1(order.AgentId, order.Uid, order.CardNum, multiOrm...)
		if err != nil {
			eventLog := map[string]interface{}{
				"module":     ModuleCash,
				"event_type": EventBonus,
				"user_type":  Agent,
				"uid":        order.AgentId,
				"msg":        fmt.Sprintf("玩家:%d直充的提成发放失败,平台订单号:%d", order.Uid, order.Id),
			}
			go NewEventLog(eventLog)
			return err
		}
	} else if u.Level == Level2 {
		err = bonusPlayerLevel2(u.Pid, order.AgentId, order.Uid, order.CardNum, multiOrm...)
		if err != nil {
			eventLog := map[string]interface{}{
				"module":     ModuleCash,
				"event_type": EventBonus,
				"user_type":  Agent,
				"uid":        u.Pid,
				"msg":        fmt.Sprintf("玩家:%d直充的提成发放失败,平台订单号:%d", order.Uid, order.Id),
			}
			go NewEventLog(eventLog)
			return err
		}
	}
	return nil
}

//直接修改代理钻石数

func ChangeH5AgentCard(uid, cardNum, operateUid int64, multiOrm ...orm.Ormer) error {
	//把成功的订单记录写到h5_card_record里
	cardRecord := map[string]interface{}{
		"agent_id":    uid,
		"card_num":    cardNum,
		"amount":      0,
		"type":        SystemGiveRoomCard,
		"pay_type":    BalancePay,
		"create_time": time.Now().Unix(),
	}
	_, err := h5.NewCardRecord(cardRecord, multiOrm...)
	if err != nil {
		return err
	}

	//给代理加上钻石数量
	_, err = h5.UpdateCard(cardNum, uid, false, multiOrm...)
	if err != nil {
		return err
	}

	err = pc.DoSystemDiamond(SysH5GiveUid, -cardNum, uid, SysOpHandOut, operateUid, Agent)
	if err != nil {
		LogClient.Error(fmt.Sprintf("从H5端系统购买帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
			SysH5GiveUid, cardNum, uid, SysOpHandOut, err))
	}
	return nil
}

//代理微信买卡发货
func DeliveryH5AgentCard(uid, cardNum, sysGiveCardNum, amount int64, orderId interface{}, multiOrm ...orm.Ormer) error {
	//把成功的订单记录写到h5_card_record里
	cardRecord := map[string]interface{}{
		"agent_id":    uid,
		"card_num":    cardNum,
		"amount":      amount,
		"type":        BuyRoomCard,
		"pay_type":    WeChatPay,
		"create_time": time.Now().Unix(),
	}
	_, err := h5.NewCardRecord(cardRecord, multiOrm...)
	if err != nil {
		return err
	}
	if sysGiveCardNum > 0 {
		sysGiveCardRecord := map[string]interface{}{
			"agent_id":    uid,
			"card_num":    sysGiveCardNum,
			"amount":      0, //系统赠送的，没有花钱
			"type":        SystemGiveRoomCard,
			"pay_type":    WeChatPay,
			"create_time": time.Now().Unix(),
		}
		_, err := h5.NewCardRecord(sysGiveCardRecord, multiOrm...)
		if err != nil {
			return err
		}
	}

	//给代理加上钻石数量
	_, err = h5.UpdateCard(cardNum+sysGiveCardNum, uid, true, multiOrm...)
	if err != nil {
		return err
	}

	//发货成功，要更新订单状态
	updateData := map[string]interface{}{
		"status":        OrderDelivered,
		"delivery_time": time.Now().Unix(),
	}
	_, err = h5.UpdateOrder(updateData, orderId)
	if err != nil {
		return err
	}

	err = pc.DoSystemDiamond(SysH5BuyUid, -cardNum, uid, SysOpBuy, -1, Agent)
	if err != nil {
		LogClient.Error(fmt.Sprintf("从H5端系统购买帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
			SysH5BuyUid, cardNum, uid, SysOpBuy, err))
	}
	if sysGiveCardNum > 0 {
		err := pc.DoSystemDiamond(SysH5GiveUid, -sysGiveCardNum, uid, SysOpBuyGive, -1, Agent)
		if err != nil {
			LogClient.Error(fmt.Sprintf("从H5端系统购买赠送帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
				SysH5GiveUid, sysGiveCardNum, uid, SysOpBuyGive, err))
		}
	}
	return nil
}

//玩家直充微信买卡发货,uid为玩家id
func DeliveryH5PlayerCard(playerId, agentId, cardNum, sysGiveCardNum, amount int64, orderId interface{}, multiOrm ...orm.Ormer) error {
	//把成功的订单记录写到h5_card_record里
	//两个都发货失败了才表示失败，这里有个问题，可能其中一个成功了，其中一个失败了，订单被更新成已发货，玩家亏了
	if (cardNum + sysGiveCardNum) > 0 {
		ok := client.ChangeAccountValueFromLobby(playerId, cardNum+sysGiveCardNum,
			0, 0, ACCTRAN_OPER_TYPE_BuyCard, 0)
		if !ok {
			eventLog := map[string]interface{}{
				"module":     ModuleSystem,
				"event_type": EventPlay,
				"user_type":  Player,
				"uid":        playerId,
				"msg":        fmt.Sprintf("发货失败,游戏服返回失败,请手动为玩家发货,平台订单号:%v", orderId),
			}
			go NewEventLog(eventLog)
			return MsgErrGame
		}

		err := pc.DoSystemDiamond(SysClientBuyUid, -cardNum, playerId, SysOpBuy, -1, Player)
		if err != nil {
			LogClient.Error(fmt.Sprintf("从客户端系统购买帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
				SysClientBuyUid, cardNum, playerId, SysOpBuy, err))
		}
		if sysGiveCardNum > 0 {
			err := pc.DoSystemDiamond(SysClientGiveUid, -sysGiveCardNum, playerId, SysOpBuyGive, -1, Player)
			if err != nil {
				LogClient.Error(fmt.Sprintf("从客户端系统购买赠送帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
					SysClientGiveUid, sysGiveCardNum, playerId, SysOpBuyGive, err))
			}
		}

	} else { //钻石都为0，不用发货
		return nil
	}

	//钻石记录(记录玩家在哪个代理买了卡,钻石数不包含系统赠送的)
	cardRecord := map[string]interface{}{
		"agent_id":    agentId,
		"player_id":   playerId,
		"card_num":    -cardNum,
		"amount":      amount,
		"type":        AutomaticTopUp,
		"pay_type":    WeChatPay,
		"create_time": time.Now().Unix(),
	}
	_, err := h5.NewCardRecord(cardRecord, multiOrm...)
	if err != nil {
		return err
	}

	if sysGiveCardNum != 0 {
		sysGiveCardRecord := map[string]interface{}{
			"agent_id":    agentId,
			"player_id":   playerId,
			"card_num":    sysGiveCardNum,
			"amount":      0, //系统赠送的，没有花钱
			"type":        SystemGiveRoomCard,
			"pay_type":    WeChatPay,
			"create_time": time.Now().Unix(),
		}
		_, err := h5.NewCardRecord(sysGiveCardRecord, multiOrm...)
		if err != nil {
			return err
		}
	}

	//发货成功，要更新订单状态
	updateData := map[string]interface{}{
		"status":        OrderDelivered,
		"delivery_time": time.Now().Unix(),
	}
	_, err = h5.UpdateOrder(updateData, orderId, multiOrm...)
	if err != nil {
		return err
	}

	//凡是在此代理充值过的玩家，不管是直充还是代充，都要记录到表里
	agentPlayer := map[string]interface{}{
		"create_time": time.Now().Unix(),
	}
	//不用管成功与否，不重要
	h5.UpdateOrInsertAgentPlayer(agentPlayer, playerId, agentId)
	return nil
}

//玩家商城买钻石发货,uid为玩家id
func DeliveryDiamond(playerId, Num int64, orderId interface{}, multiOrm ...orm.Ormer) error {
	ok := client.ChangeAccountValueFromLobby(playerId, Num,
		0, 0, ACCTRAN_OPER_TYPE_BuyCard, 0)
	if !ok {
		//发送邮件通知
		data := map[string]interface{}{
			"type":      EmailTypePay,
			"suid":      0,
			"ruid":      playerId,
			"nickname":  "系统消息",
			"title":     "钻石到账失败通知",
			"content":   fmt.Sprintf("您购买钻石(%v)未到账,请联系客服", Num),
			"status":    0,
			"send_time": time.Now().Unix(),
		}
		client.SendEmailAndNotifyClient(data, playerId, 0, "")

		eventLog := map[string]interface{}{
			"module":     ModuleSystem,
			"event_type": EventPlay,
			"user_type":  Player,
			"uid":        playerId,
			"msg":        fmt.Sprintf("发货失败,游戏服返回失败,请手动为玩家发货,平台订单号:%v", orderId),
		}

		go NewEventLog(eventLog)
		return MsgErrGame
	}
	//发送邮件通知
	data := map[string]interface{}{
		"type":      EmailTypePay,
		"suid":      0,
		"ruid":      playerId,
		"nickname":  "系统消息",
		"title":     "钻石到账通知",
		"content":   fmt.Sprintf("您购买钻石(%v)已到账,请查收", Num),
		"status":    0,
		"send_time": time.Now().Unix(),
	}
	client.SendEmailAndNotifyClient(data, playerId, 0, "")

	err := pc.DoSystemDiamond(SysClientBuyUid, -Num, playerId, SysOpBuy, -1, Player)
	if err != nil {
		LogClient.Error(fmt.Sprintf("从客户端系统购买帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
			SysClientBuyUid, Num, playerId, SysOpBuy, err))
	}

	//发货成功，要更新订单状态
	updateData := map[string]interface{}{
		"status":        OrderDelivered,
		"delivery_time": time.Now().Unix(),
	}
	_, err = client.UpdateOrder(updateData, orderId, multiOrm...)

	return err
}

//代理刚开通,初始化
func InitAgent(uid, openFee int64) error {
	//获取上级代理的uid
	field := []string{"pid", "level", "status"}
	pu, err := h5.SpecifyUserInfoById(uid, field)
	if err != nil {
		return err
	}
	if pu == nil {
		LogH5.Error(fmt.Sprintf("此代理(ID:%v)不存在", uid))
		return errors.New(fmt.Sprintf("此代理(ID:%v)不存在", uid))
	}
	if pu.Status == FirstTopUpSuccess {
		return MsgAgentAlreadyFormal
	}

	//1.如果说是一级代理,要生成一个授权码
	if pu.Level == Level1 {
		//如果授权码方面出错了不能影响到其它方面,所以不能立即返回错误
		_, err := GenOrUpdateAuthCode(uid, Level2)
		if err != nil {
			LogH5.Error(err.Error())
		}
	}

	//2.要在h5_card_cash增加一条记录
	cc := map[string]interface{}{
		"uid":      uid,
		"open_fee": openFee, //开通费用
	}
	_, err = h5.NewCardCash(cc)
	if err != nil {
		return err
	}
	//获取一级代理能开的代理数
	rule, err := h5.RuleByType(RuleAgentNum)
	if err != nil {
		LogH5.Error(err.Error())
	}

	//3.改变用户的状态为正式代理及设定代理初始化名额
	updateUserData := map[string]interface{}{
		"status":     FirstTopUpSuccess,
		"agent_time": time.Now().Unix(), //成为正式代理的时间
	}
	if pu.Level == Level1 { //一级代理要设置代理名额
		updateUserData["agent_num"] = rule.Amount
	} else { //二级代理没有代理名额
		updateUserData["agent_num"] = 0
	}

	n, err := h5.UpdateUser(updateUserData, uid)
	if err != nil || n == 0 {
		return err
	}
	return nil
}

//创建或更新授权码
func GenOrUpdateAuthCode(uid, level int64) (string, error) {
	var newAuthCode string
	//授权码20次都冲突的话，说明授权码范围太小了，要重新设计
	for i := 0; i < 20; i++ {
		newAuthCode = GenerateAuthCode()
		newAc, err := h5.IsAuthCodeExist(newAuthCode)
		if err != nil {
			return "", err
		}
		//授权码不存在,跳出循环
		if newAc.AuthCode == "" {
			break
		}
		if i >= 19 {
			log := map[string]interface{}{
				"module":     ModuleSystem,
				"event_type": EventAgent,
				"user_type":  Agent,
				"uid":        uid,
				"msg":        "生成授权码失败",
			}
			go NewEventLog(log)
			LogH5.Warning(fmt.Sprintf("循环20次授权码还是冲突了，代理:%v", uid))
		}

	}
	data := map[string]interface{}{
		"uid":         uid,
		"level":       level,
		"auth_code":   newAuthCode,
		"create_time": time.Now().Unix(),
	}
	_, err := h5.NewOrUpdateAuthCode(data)
	return newAuthCode, err
}

//----------------------------------------------以下是合伙人模式下的------------------------------

//合伙人模式的代理刚开通,初始化
func InitPartnerAgent(uid, openFee int64) error {
	//获取上级代理的pid及自己的信息
	field := []string{"pid", "level", "status", "group_id", "root_id"}
	pu, err := partner.SpecifyUserInfoById(uid, field)
	if err != nil {
		return err
	}
	if pu == nil {
		LogPF.Error(fmt.Sprintf("此代理(ID:%v)不存在", uid))
		return errors.New(fmt.Sprintf("此代理(ID:%v)不存在", uid))
	}
	if pu.Status == FirstTopUpSuccess {
		return MsgAgentAlreadyFormal
	}

	//1.要在partner_card_cash增加一条记录
	cc := map[string]interface{}{
		"uid":      uid,
		"open_fee": openFee, //开通费用
	}
	_, err = partner.NewCardCash(cc)
	if err != nil {
		return err
	}
	//2.获取代理能开的代理数
	rule, err := partner.RuleByType(RuleAgentNum)
	if err != nil {
		LogPF.Error(err.Error())
	}

	//3.改变用户的状态为正式代理及设定代理初始化名额
	updateUserData := map[string]interface{}{
		"status":     FirstTopUpSuccess,
		"agent_time": time.Now().Unix(), //成为正式代理的时间
		"agent_num":  rule.Amount,
	}
	_, err = partner.UpdateUser(updateUserData, uid)

	//4.更新agent_player表里group_id, root_id
	data := map[string]interface{}{
		"group_id": pu.GroupId,
		"root_id":  pu.RootId,
	}
	partner.UpdateAgentPlayer(data, uid)
	return err
}

//给合伙人模式下的代理发货
func DeliveryPfAgentCard(uid, cardNum, sysGiveCardNum, amount int64, orderId interface{}, multiOrm ...orm.Ormer) error {
	//把成功的订单记录写到h5_card_record里
	cardRecord := map[string]interface{}{
		"agent_id":    uid,
		"card_num":    cardNum,
		"amount":      amount,
		"type":        BuyRoomCard,
		"pay_type":    WeChatPay,
		"create_time": time.Now().Unix(),
	}
	_, err := partner.NewCardRecord(cardRecord, multiOrm...)
	if err != nil {
		return err
	}
	if sysGiveCardNum > 0 {
		sysGiveCardRecord := map[string]interface{}{
			"agent_id":    uid,
			"card_num":    sysGiveCardNum,
			"amount":      0, //系统赠送的，没有花钱
			"type":        SystemGiveRoomCard,
			"pay_type":    WeChatPay,
			"create_time": time.Now().Unix(),
		}
		_, err := partner.NewCardRecord(sysGiveCardRecord, multiOrm...)
		if err != nil {
			return err
		}
	}

	//给代理加上钻石数量
	_, err = partner.UpdateCard(cardNum+sysGiveCardNum, uid, true, multiOrm...)
	if err != nil {
		return err
	}

	//发货成功，要更新订单状态
	updateData := map[string]interface{}{
		"status":        OrderDelivered,
		"delivery_time": time.Now().Unix(),
	}
	_, err = partner.UpdateOrder(updateData, orderId)
	if err != nil {
		return err
	}

	err = pc.DoSystemDiamond(SysPfBuyUid, -cardNum, uid, SysOpBuy, -1, Agent)
	if err != nil {
		LogPF.Error(fmt.Sprintf("从Pf端系统购买帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
			SysPfBuyUid, cardNum, uid, SysOpBuy, err))
	}
	if sysGiveCardNum > 0 {
		err := pc.DoSystemDiamond(SysPfGiveUid, -sysGiveCardNum, uid, SysOpBuyGive, -1, Agent)
		if err != nil {
			LogPF.Error(fmt.Sprintf("从Pf端系统购买赠送帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
				SysPfGiveUid, sysGiveCardNum, uid, SysOpBuyGive, err))
		}
	}

	return nil
}

//合伙人系统，直接代充游戏ID里去
func PfTopUp2GameId(uid, cardNum int64) error {
	//发完货直接代充到代理的游戏ID(代理的ID与游戏ID相同)
	ok := client.ChangeAccountValueFromLobby(uid, cardNum,
		0, 0, ACCTRAN_OPER_TYPE_BuyCard, 0)
	if !ok {
		eventLog := map[string]interface{}{
			"module":     ModuleSystem,
			"event_type": EventPlay,
			"user_type":  Agent,
			"uid":        uid,
			"msg":        fmt.Sprintf("游戏服返回失败,代充失败,请联系开发人员"),
		}
		go NewEventLog(eventLog)
		LogPF.Error(fmt.Sprintf("游戏服返回失败,合伙人(ID:%v)充值钻石到自己的游戏ID里失败", uid))
		return nil
	}

	o := NewDBOrm(DBChessPartner)
	o.Begin()
	defer o.Rollback()
	//代充记录
	handleCR := map[string]interface{}{
		"agent_id":    uid,
		"player_id":   uid,
		"card_num":    -cardNum,
		"type":        HandleTopUp,
		"create_time": time.Now().Unix(),
	}

	_, err := partner.NewCardRecord(handleCR, o)
	if err != nil {
		o.Rollback()
		LogPF.Error(fmt.Sprintf("记录房卡变动记录时失败:%v", err))
		return err
	}
	_, err = partner.UpdateCard(-cardNum, uid, false, o)
	if err != nil {
		o.Rollback()
		LogPF.Error(fmt.Sprintf("合伙人购买的直接充值到游戏ID成功,但在减少房卡时失败了:%v", err))
		return err
	}
	return o.Commit()
}

//(依次发放提成,从下往上,首先给自己提成,然后上一级,然后再上一级.......总代,合伙人)
func BonusPfAgent(uid, cardNum, amount int64, multiOrm ...orm.Ormer) error {
	/*
	 1. 首先找出总代里的总代提成,直属一级提成,直属二级提成
	 2. 然后判断自己是什么级别
	*/

	/*group_id为合伙人的ID,pid为上级代理的ID,root_id为总代的id,
	bonus_rate为总代的提成,bonus_rate1为直属一级提成,bonus_rate2为直属二级提成
	*/
	field := []string{"pid", "level", "group_id", "root_id", "bonus_rate", "bonus_rate1", "bonus_rate2"}
	self, err := partner.SpecifyUserInfoById(uid, field)
	if err != nil {
		return err
	}
	if self == nil {
		return errors.New(fmt.Sprintf("代理(ID:%v)在partner_user没有找到", uid))
	}

	var (
		cBonusRate  int64 //公司的提成比例
		pfBonusRate int64 //合伙人的提成比例
		rBonusRate  int64 //总代的提成比例
		bonusRate1  int64 //直属一级的提成比例
		bonusRate2  int64 //直属二级的提成比例
		rrBonusRate int64 //总代的固定提成比例
	)

	if self.Level != Level1 { //不是总代
		field = []string{"bonus_rate", "bonus_rate1", "bonus_rate2"}
		root, err := partner.SpecifyUserInfoById(self.RootId, field)
		if err != nil {
			return err
		}
		if root == nil {
			return errors.New(fmt.Sprintf("代理(ID:%v)在partner_user没有找到", self.RootId))
		}
		bonusRate1 = root.BonusRate1
		bonusRate2 = root.BonusRate2
		rBonusRate = root.BonusRate
	} else {
		bonusRate1 = self.BonusRate1
		bonusRate2 = self.BonusRate2
		rBonusRate = self.BonusRate
	}

	//公司的提成比例
	cBonusRate, err = pb.CompanyBonusById(self.GroupId)
	if err != nil {
		msg := fmt.Sprintf("查找合伙人(ID:%v)失败:%v", self.GroupId, err)
		LogPF.Error(msg)
		return errors.New(msg)
	}
	//公司的提成
	cBonusAmount := cBonusRate * amount / 10000
	err = BonusCompany(self.GroupId, cardNum, amount, cBonusAmount, multiOrm...)
	if err != nil {
		msg := fmt.Sprintf("代理(ID:%v)充值(%v分),给公司提成时失败:%v",
			uid, amount, err)
		LogPF.Error(msg)
		return errors.New(msg)
	}
	//合伙人的提成比例
	pfBonusRate = 10000 - cBonusRate - rBonusRate
	//合伙人的提成
	pfBonusAmount := pfBonusRate * amount / 10000
	err = BonusPb(self.GroupId, self.RootId, cardNum, pfBonusAmount, amount, multiOrm...)
	if err != nil {
		msg := fmt.Sprintf("代理(ID:%v)充值(%v分)给合伙人(ID:%v)提成(%v分)失败:%v",
			uid, amount, self.GroupId, pfBonusAmount, err)
		LogPF.Error(msg)
		return errors.New(msg)
	}
	//---------------------下面给总代提成----------------------------
	//总代的固定收入提成比例
	rrBonusRate = rBonusRate - bonusRate1 - bonusRate2

	if self.Level == Level1 { //总代充值
		rBonusAmount := rBonusRate * amount / 10000
		err = BonusPf(uid, uid, cardNum, rBonusAmount, amount, multiOrm...)
		if err != nil {
			msg := fmt.Sprintf("代理(ID:%v)充值(%v分)给代理(ID:%v)提成(%v分)失败:%v",
				uid, amount, uid, rBonusAmount, err)
			LogPF.Error(msg)
			return errors.New(msg)
		}
	} else if self.Level == Level2 { //总代下一级充值
		//总代的收入为固定收入提成比例加上直属一级提成比例
		rBonusAmount := (rrBonusRate + bonusRate1) * amount / 10000
		err = BonusPf(self.RootId, uid, cardNum, rBonusAmount, amount, multiOrm...)
		if err != nil {
			msg := fmt.Sprintf("代理(ID:%v)充值(%v分)给代理(ID:%v)提成(%v分)失败:%v",
				uid, amount, uid, rBonusAmount, err)
			LogPF.Error(msg)
			return errors.New(msg)
		}
		//代理的提成收入为总代的提成减去总的固定提成收入及直属一级的,则等于直属二级的提成收入
		bonusAmount := bonusRate2 * amount / 10000
		err = BonusPf(uid, uid, cardNum, bonusAmount, amount, multiOrm...)
		if err != nil {
			msg := fmt.Sprintf("代理(ID:%v)充值(%v分)给代理(ID:%v)提成(%v分)失败:%v",
				uid, amount, uid, bonusAmount, err)
			LogPF.Error(msg)
			return errors.New(msg)
		}

	} else if self.Level == Level3 { //总代下二级充值
		//总代的收入为固定收入提成比例加上直属二级提成比例
		rBonusAmount := (rrBonusRate + bonusRate2) * amount / 10000
		err = BonusPf(self.RootId, uid, cardNum, rBonusAmount, amount, multiOrm...)
		if err != nil {
			msg := fmt.Sprintf("代理(ID:%v)充值(%v分)给代理(ID:%v)提成(%v分)失败:%v",
				uid, amount, self.RootId, rBonusAmount, err)
			LogPF.Error(msg)
			return errors.New(msg)
		}
		//上级提成比例(代理为level2)提成比例为直属一级的提成比例
		bonusAmount := bonusRate1 * amount / 10000
		err = BonusPf(self.Pid, uid, cardNum, bonusAmount, amount, multiOrm...)
		if err != nil {
			msg := fmt.Sprintf("代理(ID:%v)充值(%v分)给代理(ID:%v)提成(%v分)失败:%v",
				uid, amount, self.Pid, bonusAmount, err)
			LogPF.Error(msg)
			return errors.New(msg)
		}

	} else { //总代下三级以下及下三级充值
		//总代的收入为固定收入提成比例
		rBonusAmount := rrBonusRate * amount / 10000
		err = BonusPf(self.RootId, uid, cardNum, rBonusAmount, amount, multiOrm...)
		if err != nil {
			msg := fmt.Sprintf("代理(ID:%v)充值(%v分)给代理(ID:%v)提成(%v分)失败:%v",
				uid, amount, self.RootId, rBonusAmount, err)
			LogPF.Error(msg)
			return errors.New(msg)
		}
		//上级的提成比例的直属一级的提成比例
		bonusAmount := bonusRate1 * amount / 10000
		err = BonusPf(self.Pid, uid, cardNum, bonusAmount, amount, multiOrm...)
		if err != nil {
			msg := fmt.Sprintf("代理(ID:%v)充值(%v分)给代理(ID:%v)提成(%v分)失败:%v",
				uid, amount, self.Pid, bonusAmount, err)
			LogPF.Error(msg)
			return errors.New(msg)
		}
		//上上级的提成比例为直属二级的提成比例
		field := []string{"pid"}
		u, err := partner.SpecifyUserInfoById(self.Pid, field)
		if err != nil {
			return err
		}
		if u == nil {
			return errors.New(fmt.Sprintf("代理(ID:%v)在partner_user没有找到", self.Pid))
		}
		bonusAmount = bonusRate2 * amount / 10000
		err = BonusPf(u.Pid, uid, cardNum, bonusAmount, amount, multiOrm...)
		if err != nil {
			msg := fmt.Sprintf("代理(ID:%v)充值(%v分)给代理(ID:%v)提成(%v分)失败:%v",
				uid, amount, u.Pid, bonusAmount, err)
			LogPF.Error(msg)
			return errors.New(msg)
		}
	}

	//记录代理充值记录
	err = PfAgentCharge(uid, amount, multiOrm...)
	if err != nil {
		msg := fmt.Sprintf("代理(ID:%v)充值(%v分),记录充值金额失败:%v",
			uid, amount, err)
		LogPF.Error(msg)
		return errors.New(msg)
	}

	return nil
}

//合伙人系统的代理提成
func BonusPf(uid, childId, cardNum, amount, cash int64, multiOrm ...orm.Ormer) error {
	if amount <= 0 {
		return nil
	}
	//加上金额
	_, err := partner.UpdateCash(amount, uid, false, multiOrm...)
	if err != nil {
		return err
	}
	//提成记录
	cr := map[string]interface{}{
		"agent_id":    uid,
		"child_id":    childId,
		"card_num":    cardNum,
		"amount":      amount, //提成金额
		"cash":        cash,   //充值金额
		"type":        PfCashAgentBonus,
		"month":       CurrentYearMonth(),
		"create_time": time.Now().Unix(),
	}
	_, err = partner.NewCashRecord(cr, multiOrm...)
	return err
}

//记录合伙人系统下的代理充值金额
func PfAgentCharge(agentId, cash int64, multiOrm ...orm.Ormer) error {
	if cash <= 0 {
		return nil
	}
	//充值记录
	cr := map[string]interface{}{
		"agent_id":    agentId,
		"child_id":    agentId,
		"card_num":    0,
		"amount":      0,    //提成金额
		"cash":        cash, //充值金额
		"type":        PfCashAgentCharge,
		"month":       CurrentYearMonth(),
		"create_time": time.Now().Unix(),
	}
	_, err := partner.NewCashRecord(cr, multiOrm...)
	return err
}

//合伙人系统的合伙人的提成
func BonusPb(uid, agentId, cardNum, amount, cash int64, multiOrm ...orm.Ormer) error {
	if amount <= 0 {
		return nil
	}
	//加上金额
	_, err := pb.UpdateCash(amount, uid, false, multiOrm...)
	if err != nil {
		return err
	}
	//提成记录
	cr := map[string]interface{}{
		"uid":         uid,
		"agent_id":    agentId,
		"card_num":    cardNum,
		"amount":      amount, //提成金额
		"cash":        cash,   //充值金额
		"type":        PfCashAgentBonus,
		"month":       CurrentYearMonth(),
		"create_time": time.Now().Unix(),
	}
	_, err = pb.NewCashRecord(cr, multiOrm...)
	return err
}

//合伙人系统的公司的提成
func BonusCompany(groupId, cardNum, amount, cash int64, multiOrm ...orm.Ormer) error {
	if amount <= 0 {
		return nil
	}
	//提成记录
	cr := map[string]interface{}{
		"group_id":    groupId,
		"card_num":    cardNum,
		"amount":      amount, //提成金额
		"cash":        cash,   //充值金额
		"month":       CurrentYearMonth(),
		"create_time": time.Now().Unix(),
	}
	_, err := pc.NewCashRecord(cr, multiOrm...)
	return err
}

//给合伙人系统代理发货
func DealPfAgentPay(order *PfOrder) error {
	/*如果说是第一次充值买卡
	  1.如果说是一级代理,要生成一个授权码
	  2.要在h5_card_cash增加一条记录
	  3.改变用户的状态为正式代理,并且把代理成为正式代理的时间(agent_time)设为当前
	*/
	//首先判断是否为第一次充值买卡,要把开通费用记录到h5_card_cash表里
	if order.IsFirst == FirstTimeBuyCard {
		err := InitPartnerAgent(order.Uid, order.Amount)
		if err != nil {
			//初始化失败
			LogPF.Error(err.Error())
			return err
		}
	}
	o := NewDBOrm(DBChessPartner)
	o.Begin()
	defer o.Rollback()

	//给代理发货
	err := DeliveryPfAgentCard(order.Uid, order.CardNum, order.GiveNum,
		order.Amount, order.Id, o)
	if err != nil {
		o.Rollback()
		eventLog := map[string]interface{}{
			"module":     ModuleCard,
			"event_type": EventDelivery,
			"user_type":  Agent,
			"uid":        order.Uid,
			"msg":        fmt.Sprintf("订单:%v发货失败,请联系开发人员", order.Id),
		}
		go NewEventLog(eventLog)
		LogPF.Error(err.Error())
		return err
	}

	//发放提成
	err = BonusPfAgent(order.Uid, order.CardNum, order.Amount, o)
	if err != nil {
		o.Rollback()
		eventLog := map[string]interface{}{
			"module":     ModuleCard,
			"event_type": EventDelivery,
			"user_type":  Agent,
			"uid":        order.Uid,
			"msg":        fmt.Sprintf("订单:%v发放提成给代理失败,请联系开发人员", order.Id),
		}
		go NewEventLog(eventLog)
		LogPF.Error(err.Error())
		return err
	}
	o.Commit()

	//直接把钻石充到合伙人的游戏ID帐号里
	err = PfTopUp2GameId(order.Uid, order.CardNum+order.GiveNum)
	if err != nil {
		LogPF.Error(err.Error())
		eventLog := map[string]interface{}{
			"module":     ModuleCard,
			"event_type": EventDelivery,
			"user_type":  Agent,
			"uid":        order.Uid,
			"msg":        fmt.Sprintf("合伙人:%v直接充值到自己的游戏ID失败,请联系开发人员", order.Uid),
		}
		go NewEventLog(eventLog)
		return err
	}
	return nil
}
